feat(agent): explicit pre-delegation gate before spawning the Report agent#95
Merged
Merged
Conversation
…agent Closes #94. Cert Ep 04's fail-fast lesson: a coordinator must verify an upstream sub-agent's structured finding before delegating to the next, and short-circuit if it is thin, or the downstream agent hallucinates on empty context. run_cycle's only gate before the Report agent was _all_claims_low_confidence, which returns False for an empty claims list, so a diagnosis with NO claims (or a parse_error fallback with none) sailed past it into the Report agent, which then synthesized a full incident from nothing. Add _verify_diagnosis_precondition(diagnosis) -> str | None, returning a reason when the diagnosis is not fit to delegate (parse-error fallback, no claims, or all claims LOW/UNSOURCED) and None when it is. run_cycle calls it in place of the inline low-confidence check; on a reason it logs and returns None without spawning the Report agent or escalating. Multi-agent path only; single-agent mode (no sub-agent claims by design) is unchanged. Tests: the gate for reportable / no-claims / parse-error / all-low, plus a run_cycle test asserting an empty diagnosis never spawns the Report agent and never escalates. Full suite 260 passed; ruff + mypy clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #94.
Problem (cert Ep 04, fail-fast delegation)
Ep 04's capstone lesson: verify an upstream sub-agent's structured finding before delegating to the next, and short-circuit if it's thin, or "the second sub-agent might also execute and return hallucinated results."
run_cycle's only gate before the Report agent was_all_claims_low_confidence, which returnsFalsefor an empty claims list:So a diagnosis with no claims (Diagnostic agent found nothing concrete) or a
parse_errorfallback (unparseable diagnostic output, no claims/sources) sailed past it into the Report agent, which then synthesized a full IncidentReport from nothing, the exact hallucinate-on-thin-context failure Ep 04 warns about.Fix
_verify_diagnosis_precondition(diagnosis) -> str | Nonereturns a reason when the diagnosis is not fit to delegate (parse-error fallback, no claims, or all claims LOW/UNSOURCED) andNonewhen it is.run_cyclecalls it in place of the inline low-confidence check; on a reason it logs and returnsNonewithout spawning the Report agent or escalating. Multi-agent path only; single-agent mode (no sub-agent claims by design) is unchanged.Tests
Gate for reportable / no-claims / parse-error / all-low, plus a
run_cycletest asserting an empty diagnosis never spawns the Report agent and never escalates.Full suite 260 passed; ruff + mypy clean.
Note on the Ep 04 task-tool caveat
Ep 04 flags that
task-based sub-agent spawning is a Claude Code / Agent SDK feature, not the raw anthropic SDK, and that hand-rolled function spawning is architecturally correct. This project already hand-rolls spawning with plain functions +asyncio.gather, so it's aligned with the pattern the exam tests; no change needed there.https://claude.ai/code/session_01R5VygSzbGTggW7mHd3PVwE